#ifndef MG_GEOMETRY_ARE_COLLINEAR_H
#define MG_GEOMETRY_ARE_COLLINEAR_H

#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/make.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/geometry.hpp>

#include "are_parallel.h"

namespace mg
{
    namespace geometry
    {
        template<typename Point1, typename Point2, typename Point3, typename Tolerance>
        bool are_collinear(const Point1& p1, const Point2& p2, const Point3& p3)
        {
            typedef typename boost::geometry::select_most_precise<
                Point1, boost::geometry::select_most_precise<Point2, Point3>::type>::type Point;
            typedef typename boost::geometry::coordinate_type<Point>::type T;
            typedef typename boost::geometry::model::point<boost::geometry::select_most_precise<T, mgreal>::type, boost::geometry::dimension<Point1>::type::value, boost::geometry::coordinate_system<Point1>::type> P;

            return are_parallel<P, P, T>(
                difference<Point1, Point2, P>(p1, p2),
                difference<Point1, Point3, P>(p1, p3));
        }

        template<typename Point1, typename Point2, typename Point3>
        inline bool are_collinear(const Point1& p1, const Point2& p2, const Point3& p3)
        {
            BOOST_CONCEPT_ASSERT((boost::geometry::concept::ConstPoint<Point1>));
            BOOST_CONCEPT_ASSERT((boost::geometry::concept::ConstPoint<Point2>));
            BOOST_CONCEPT_ASSERT((boost::geometry::concept::ConstPoint<Point3>));

            typedef typename boost::geometry::select_most_precise<
                Point1, boost::geometry::select_most_precise<Point2, Point3>::type>::type Point;
            typedef typename boost::geometry::coordinate_type<Point>::type T;

            return are_collinear<Point1, Point2, Point3, T>(p1, p2, p3);
        }
    }
}

#endif